package com.domcer.ultra.menu.domain;

import com.domcer.ultra.menu.common.constants.I18nKeyMenuEnum;
import com.domcer.ultra.menu.common.constants.MenuConstant;
import common.utils.MessageUtil;
import lombok.*;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;

import java.io.File;
import java.io.Reader;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author hang.wang
 * @Date 2025/1/30 22:41
 */
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MenuDomain {
    private MenuSettingsDomain menuSettings;
    private Map<String, MenuItemDomain> items;
    private Map<Integer, MenuItemDomain> itemsBySlot;

    /**
     * custom parse menu to {@link MenuDomain} <br>
     * why not use {@link org.yaml.snakeyaml.Yaml#loadAs(Reader, Class)} <br>
     * because of not intelligent, with many errors and no scalability <br>
     * for the sake of concise and standardized code <br>
     * put the tedious data assembly process into the assembly method in the entity class <br>
     * but not within this method (ugly and bloated)
     * @param file {@link File}
     * @return {@link MenuDomain} one file corresponding one {@link MenuDomain}
     */
    public static MenuDomain assemble(File file) {
        try {
            FileConfiguration config = YamlConfiguration.loadConfiguration(file);
            MenuDomain menu = new MenuDomain();

            if (config.contains(MenuConstant.MENU_SETTINGS)) {
                ConfigurationSection section = config.getConfigurationSection(MenuConstant.MENU_SETTINGS);
                MenuSettingsDomain menuSettingsDomain = MenuSettingsDomain.assemble(section);
                menu.setMenuSettings(menuSettingsDomain);
            } else {
                MessageUtil.error(I18nKeyMenuEnum.MENU_SETTINGS_IS_MISSING, file.getName());
            }

            Map<String, MenuItemDomain> items = new HashMap<>();
            for (String key : config.getKeys(false)) {
                ConfigurationSection section = config.getConfigurationSection(key);

                // when writing the code here, I was thinking about the requirements
                // I was wondering what the essence of development is
                // whether it is to meet the diversity of functional requirements or to focus on user experience
                // obviously, I chose the latter because for the convenience of the code
                // I could have placed each MenuItem at the same level as MenuSettings
                // I chose MenuSettings and MenuItems because I was worried
                // that the indentation in YML format would be too bulky
                // if you have a better idea, please change the code here
                // every time you have to judge whether the key is MenuSettings, it is really not elegant
                if (!key.equals(MenuConstant.MENU_SETTINGS)) {
                    MenuItemDomain menuItemDomain = MenuItemDomain.assemble(section);
                    items.put(key, menuItemDomain);
                }
            }
            menu.setItems(items);

            Map<Integer, MenuItemDomain> itemsBySlot = items.values().stream()
                    .collect(Collectors.toMap(MenuItemDomain::getSlot, Function.identity()));
            menu.setItemsBySlot(itemsBySlot);

            return menu;
        } catch (Exception e) {
            MessageUtil.error("error: " + e.getMessage());
            return null;
        }
    }
}
